home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Ken Long / NewStringArt-c / Think / NewStringArt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-04  |  11.6 KB  |  378 lines  |  [TEXT/KAHL]

  1. /*
  2.  *    StringArt    May 1985    Ron Hitchens
  3.  *
  4.  *    hitchens@ut-sally.ARPA    ihnp4!ut-sally!hitchens.UUCP
  5.  *
  6.  *    This program was adapted from a demo for the Sun Microsystems
  7.  *    Unix workstation
  8.  *    Ported to the Mac May 10, 1985 by Ron Hitchens
  9.  *
  10.  *    It runs a lot faster on the Sun, even though it's also 68000 based
  11.  *    and is running multituser Unix 4.2BSD, has more layers of software
  12.  *    between you and the screen, and is computing coordinates using
  13.  *    floating point.  It's clock rate is faster, and it's vector drawing
  14.  *    routines are coded for 1-bit-wide lines, but even so...
  15.  *
  16.  *    This program is public domain.  It may be be freely distributed,
  17.  *    copied and used.  All I ask is that my name and this notice remain
  18.  *    on it.  And that modifications be noted in this source listing and
  19.  *    returned to me if possible at the above email address.
  20.  *
  21.  *    History:
  22.  *        May 85    Hitchens    Created.
  23.  *        May 28    Hitchens    Look at screen size vars, add comments
  24.  *
  25.  *
  26.  *    Compilation instructions with Megamax C:
  27.  *    You need the C source files stringart.c and gennums.c
  28.  *        1. compile and link gennums.c
  29.  *        2. run gennums, it creates a C source file named stringnums.c
  30.  *          This name is hard-coded in gennums.c
  31.  *        3. Compile stringnums.c, but don't link it.  Keep stringnums.o
  32.  *        4. Compile stringart.c
  33.  *        5. Link stringart.o and stringnums.o together to make stringart
  34.  *        6. Run StringArt.
  35.  *        7. Sit back and enjoy the show.
  36.  *    If you make changes to stringart, after doing the above, you can skip
  37.  *    to 4.  Stringnums doesn't need to be re-compiled.
  38.  *    If you want to port this to another flavor of C you're on your own.
  39.  *
  40.  *    The icon was created manually with the resource editor, to retain
  41.  *    the icon when recompiling just specify the name of the old 
  42.  *    StringArt application file as the output of the linker.  It will
  43.  *    overwrite the code but won't disturb the icon resources.
  44.  */
  45.  
  46. /*
  47.     This demo creates random vector designs.  This is accomplished by
  48.     randomly choosing a function for each coordinate halve of the two
  49.     points describing a vector that moves through two dimensional
  50.     space. Both x coordinate halves cannot be the same since the design
  51.     would simply be a collection of vertical lines. Similarly both
  52.     y coordinate halves cannot be the same.
  53.  
  54.     The functions are:
  55.  
  56.     function[0][x] = sin( 2 * PI * x / numLines )
  57.     function[1][x] = -sin( 2 * PI * x / numLines )
  58.     function[2][x] = cos( 2 * PI * x / numLines ) 
  59.     function[3][x] = -cos( 2 * PI * x / numLines ) 
  60.     function[4][x] = sin( 4 * PI * x / numLines )
  61.     function[5][x] = -sin( 4 * PI * x / numLines )
  62.     function[6][x] = cos( 4 * PI * x / numLines ) 
  63.     function[7][x] = -cos( 4 * PI * x / numLines ) 
  64.     function[8][x] = sin( 6 * PI * x / numLines )
  65.     function[9][x] = -sin( 6 * PI * x / numLines )
  66.     function[10][x] = cos( 6 * PI * x / numLines ) 
  67.     function[11][x] = -cos( 6 * PI * x / numLines ) 
  68.     function[12][x] = 2 * abs( x - (numLines / 2) - 1 )    *not used*
  69.  
  70.     The values of the functions were pre-computed to have the demo
  71.     run as fast as possible.  The program runs in an endless loop, it 
  72.     will terminate if the "Quit" menu item is selected or a 'Q' is typed.
  73. */
  74.  
  75. #define numLines    343    /* number of vectors in a design */
  76. #define num_functions    12    /* number of functions */
  77. #define Voffset        19    /* offset from top, drag is under menu bar */
  78. #define border        2    /* surrounding blank border */
  79.                 
  80. /* get real size of screen, in case of Lisa or something new */
  81. #define Hsize (qd.screenBits.bounds.right)
  82. #define Vsize (qd.screenBits.bounds.bottom)
  83.  
  84. WindowRecord    myRecord;    /* if you can't figure out what these are */
  85. WindowPtr    myWindow;    /* you'd better give up right now */
  86. MenuHandle    myMenu;
  87.  
  88. int holding = 0;        /* are we currently holding? */
  89. int step = 0;            /* single step? */
  90.  
  91. int q [4][numLines];        /* temp array for scaled coordinates */
  92. extern int p [num_functions][numLines];
  93.     /* pre-computed points, scaled by 1024 */
  94.  
  95. main()
  96. {
  97.     int i, j, k, l, m;
  98.     long secs;
  99.     
  100.     Init ();        /* do housekeeping */
  101.     ShowInfo ();        /* display bragging info */
  102.     GetDateTime (&qd.randSeed);    /* randomize the Random() function */
  103.  
  104.     while (1) {        /* main loop, go round and round forever */
  105.         /* pick the functions */
  106.         while ((i = Random() % num_functions) < 0) /* nothing */ ;
  107.         while ((j = Random() % num_functions) == i || (j < 0));
  108.         while ((k = Random() % num_functions) < 0);
  109.         while ((l = Random() % num_functions) == k || (l < 0));
  110.  
  111.         /* scalepoints was a hack to speed up the line drawing, by
  112.           avoiding the scaling computations for each coordinate
  113.           while the lines are being drawn.  It didn't help as much
  114.           as I'd hoped, only about a second is saved, maybe less.
  115.           Apparently I'm pushing QuickDraw as fast as it will go.
  116.           The same calculations using floating point took about
  117.           45 seconds, YOW! */
  118.             
  119.         ScalePoints (i, k, j, l);    /* scale to the window */
  120.         while (holding && !step)    /* loop here if holding */
  121.             CheckMenu ();        /* watch events when holding */
  122.  
  123.         BlankWindow (myWindow);        /* clear to black or white */
  124.         SetPort (myWindow);        /* point QD at my window */
  125.             /* the above statement shouldn't be necessary, but
  126.               something sneaky, like the screensaver DA, could
  127.               be lurking in the darkness and may change the
  128.               grafport out from under us.  Grrr... */
  129.         ObscureCursor ();        /* get rid of the cursor */
  130.  
  131.         for (m = 0; m < numLines; m++) {    /* draw the vectors */
  132.             MoveTo (q [0][m], q [1][m]);
  133.             LineTo (q [2][m], q [3][m]);
  134.         }
  135.  
  136.         SystemTask ();            /* in case of DAs */
  137.         if (!holding) 
  138.             Sleep (6);    /* pause for ~6 secs */
  139.         step = 0;            /* only good for one shot */
  140.     }
  141. }
  142.  
  143.  
  144. /* the numbers in the array p were pre-computed using floating point
  145.    arithmetic, they were all sin or cos functions and so yielded
  146.    numbers [-1, 1].  These numbers were then scaled up by 1024 so they
  147.    could be stored as integers.  1024 was used so they could be scaled down
  148.    again with a shift-right-10 rather than a divide operation.  I use two
  149.    statements to compute each number to be sure the intermediate values
  150.    are calculated as longs, the values involved far exceed the magnitude
  151.    possible in a 16-bit int.  */
  152.      
  153. ScalePoints (x1, y1, x2, y2)    int x1, y1, x2, y2;
  154. {
  155.     long  l, h, v;
  156.     int i;
  157.     
  158.     h = (Hsize) / 2;
  159.     v = (Vsize - Voffset) / 2;
  160.     for (i = 0; i < numLines; i++) {
  161.         l = (((long)p [x1][i] * (h - border)) >> 10) + h;
  162.         q [0][i] = (int)l;
  163.         l = (((long)p [y1][i] * (v - border)) >> 10) + v;
  164.         q [1][i] = (int)l;
  165.         l = (((long)p [x2][i] * (h - border)) >> 10) + h;
  166.         q [2][i] = (int)l;
  167.         l = (((long)p [y2][i] * (v - border)) >> 10) + v;
  168.         q [3][i] = (int)l;
  169.         CheckMenu ();    /* see if there are any events to be handled */
  170.     }
  171. }
  172.  
  173.  
  174. CheckMenu ()
  175.     /* test for and handle any events, such as keyboard and mouse */
  176. {
  177.     EventRecord    theEvent;
  178.     WindowPtr    tmpPtr;
  179.  
  180.             /* loop as long as there are events in the queue */
  181.     while (GetNextEvent (everyEvent, &theEvent)) {
  182.         switch (theEvent.what) 
  183.         {
  184. //            case abortEvt:        /* something is telling us to stop */
  185. //                exit (0);
  186.             case keyDown:        /* got a key */
  187.                     /* does this key belong to a menu? */
  188.                 if (MenuKey ((char) (theEvent.message % 256))) 
  189.                 {    /* yes */
  190.                     Do_Menu (MenuKey ((char) (theEvent.message % 256)));
  191.                 } 
  192.                 else 
  193.                     {
  194.                         step = 1;    /* step once (undoc feature) */    
  195.                         return;
  196.                 }
  197.             break;
  198.             
  199.             case mouseDown:        /* mouse clicked */
  200.                 if (FindWindow(theEvent.where, &tmpPtr) == inMenuBar)
  201.                 {
  202.                     Do_Menu (MenuSelect (theEvent.where));
  203.                 } else {
  204.                     step = 1;    /* cycle once */
  205.                 }
  206.             break;
  207.     
  208.             case updateEvt:    /* always get one of these at startup */
  209.                 BeginUpdate (myWindow);
  210.                 EndUpdate (myWindow);    /* only way to get rid of it */
  211.             break;
  212.         
  213.             case nullEvent:    /* shouldn't happen, filtered above */
  214.                 return;
  215.         
  216.             default:
  217.             break;        /* not interested in anything else */
  218.         }
  219.     }
  220. }
  221.  
  222. Do_Menu (item)        long item;    /* handle a menu selection */
  223. {
  224.     HiliteMenu (1);
  225.     switch (item) 
  226.     {
  227.         case 0x00010001:        /* menu 1, item 1 (hold) */
  228.             Toggle_Hold ();
  229.         break;
  230.         
  231.         case 0x00010002:        /* menu 1, item 2 (invert) */
  232.             Invert ();
  233.         break;
  234.         
  235.         case 0x00010003:        /* menu 1, item 3 (author info) */
  236.             ShowInfo ();
  237.         break;
  238.         
  239.         case 0x00010004:        /* menu1, item 4 (quit) */
  240.             exit (0);
  241.     }
  242.     HiliteMenu (0);
  243. }
  244.     
  245.  
  246. Toggle_Hold ()
  247. {
  248.     holding = !holding;        /* toggle the flag */
  249.     CheckItem (myMenu, 1,  holding);
  250.         /* place or remove checkmark, depending on holding */
  251. }
  252.  
  253. Invert ()
  254. {
  255.     SetPort (myWindow);            /* on the off chance... */
  256.     if (myWindow->pnMode == patBic) {
  257.         PenMode (patCopy);            /* draw black */
  258.         TextMode (srcCopy);
  259.     } 
  260.     else 
  261.         {
  262.             PenMode (patBic);            /* draw white */
  263.             TextMode (srcBic);
  264.     }
  265.     InvertRect (&myWindow->portRect);    /* flip what's onscreen */
  266. }
  267.             
  268.  
  269. Init ()                    /* do initial housekeeping chores */
  270. {
  271.     ManagerInits ();
  272.     WindowInits ();
  273.     MenuInits ();
  274. }
  275.  
  276. ManagerInits()
  277. {
  278.        InitGraf(&thePort);        /* initialize qd (theport in qd) */
  279.     InitFonts();            /* initialize font manager */
  280.     InitWindows();            /* initialize window manager */
  281.     InitMenus();            /* initialize menus */
  282.     InitCursor();            /* set cursor to arrow */
  283.     FlushEvents(everyEvent, 0);    /* lose any outstanding events */
  284. }
  285.  
  286. WindowInits()
  287. {
  288.     Rect        tempRect;
  289.     
  290.     SetRect(&tempRect, 0, Voffset, Hsize, Vsize);
  291.     myWindow = NewWindow(&myRecord, &tempRect, "\pStringart", 1, 0,
  292.                 (WindowPtr)-1L, 0, (long) 0);
  293.     SetPort(myWindow);        /* draw in my window */
  294.     SelectWindow(myWindow);        /* make mine active */
  295.     PenNormal ();            /* make sure pen has defaults */
  296.     PenMode (patBic);        /* make it draw white */
  297.     TextMode (srcBic);        /* make text draw white */
  298.     TextFont (0);            /* use system font */
  299.     TextFace ((short) bold);    /* use a fancy text style */
  300. }
  301.  
  302. MenuInits ()
  303. {
  304.     myMenu = NewMenu (1, "\pStringArt");    /* allocate a menu struct */
  305.     AppendMenu (myMenu,  "\pHold/H");        /* load the item values */
  306.     AppendMenu (myMenu, "\pInvert/I");
  307.     AppendMenu (myMenu, "\pAuthor Info/A");
  308.     AppendMenu (myMenu, "\pQuit/Q");
  309.     InsertMenu (myMenu, 0);            /* let the OS know about it */
  310.     DrawMenuBar ();                /* make it show up */
  311. }
  312.  
  313. Sleep (s)    int s;
  314.     /* sleep for approx s seconds, could vary from s-1 to s seconds */
  315. {
  316.     long s1, s2;
  317.  
  318.     GetDateTime (&s1);        /* what time is it now? */
  319.     s1 += s;            /* looking for now + s seconds */
  320.     while (1) 
  321.     {
  322.         GetDateTime (&s2);
  323.         if (s1 <= s2) 
  324.             break;    /* ok, the time has come */
  325.         CheckMenu ();        /* keep an eye on events around you */
  326.     }
  327. }
  328.  
  329. BlankWindow (w)        WindowPtr w;
  330. {
  331.     if (w->pnMode == patBic) 
  332.     {    /* drawing white? */
  333.         FillRect (&w->portRect, qd.black); /* yes, paint window black */
  334.     } 
  335.     else 
  336.         {
  337.             FillRect (&w->portRect, qd.white); /* no, paint it white */
  338.     }
  339. }
  340.  
  341. ShowInfo ()        /* display bragging info */
  342. {
  343.     static char *s [] = {
  344.         "\pStringArt by Ron Hitchens.",
  345.         "\p13 September 1985.",
  346.         "\phitchens@ut-sally.ARPA  or  ...!ihnp4!ut-sally!hitchens.UUCP",
  347.         "\p", "\pWritten in MegaMax C.",
  348.         "\pThis program is public domain.", "\p",
  349.         "\pWhile in Hold, click mouse to single step",
  350.         "\pTo save an image, type:  SHIFT/CMD/3. (duh)" ,
  351.         "\pTo print an image, type:  SHIFT/CMD/4. (duh)",
  352.          "\p", "\pMade to run in THINK C™ as",
  353.         "\pan itty bitty bytes™ rehab project, ",
  354.         "\pperpetrated by Kenneth A. Long - 28 June 1994." };
  355.     int i, n;
  356.     static int busy = 0;
  357.     
  358.     HiliteMenu (1);            /* turn on the menu */
  359.     if (busy) return;        /* info screen already up */
  360.     busy = 1;            /* to prevent recursive displays */
  361.     SetPort (myWindow);        /* just in case */
  362.     ObscureCursor ();        /* get rid of the cursor */
  363.     BlankWindow (myWindow);
  364.     n = sizeof (s) / sizeof (s [0]);    /* how many lines of text? */
  365.     TextSize (24);                /* get fancy for first line */
  366.     for (i = 0; i < n; i++) {        /* display all the text */
  367.         MoveTo ((Hsize / 2) - (StringWidth (s [i]) / 2),
  368.             (Vsize / (n + 1)) + (i * (Vsize / (n + 1))));
  369.         DrawString (s [i]);    /* draw one of the text lines */
  370.         TextSize (12);        /* back to normal for the rest */
  371.     }
  372.     if (!holding) 
  373.         Sleep (10);        /* wait a bit */
  374.     HiliteMenu (0);                /* turn off the menu */
  375.     busy = 0;                /* ok, I'm finished */
  376. }
  377.  
  378.